package com.wlc.base.reflexdemo;


import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

/**
 * @author 王立朝 wanglichao@champion-credit.com
 * @description test
 * @date 2021-08-07 11:52
 */
public class Test {
    private static final String HERO_NAME = "com.wlc.base.reflexdemo.Hero";
    private static final String SRC = "/Users/wanglichao/Desktop/temp/heroConfig.txt";
    private static final String SRC2 = "/Users/wanglichao/Desktop/temp/b.txt";

    public static void main(String[] args) {
        new Test().method();

    }

    /**
     * 反射的应用
     */
     public void method(){
       File file = new File(SRC2);
         Properties properties = new Properties();
         try {
             properties.load(new FileInputStream(file));
             // 方法名和类名
             String className = (String) properties.get("class");
             String method = (String) properties.get("method");
             //通过反射获取对象，并执行
             // 获取类对象
             Class<?> aClass = Class.forName(className);
             // 获取构造器
             Constructor<?> constructor = aClass.getConstructor();
             // 通过构造器实例一个对象
             Object o = constructor.newInstance();
             // 执行方法
             Method method1 = aClass.getMethod(method);
             // //调用对象的指定方法
             method1.invoke(o);
         } catch (Exception e) {
             e.printStackTrace();
         }
     }

    /**
     * 使用反射获取对象的方法
     */
    public void getObjectMethod() {

        try {
            // 获取对象
            Hero hero = (Hero) Hero.class.getConstructor().newInstance();
            // 通过反射获取方法
            Method adAttack = Hero.class.getMethod("adAttack");
            // 通过反射执行方法
            adAttack.invoke(hero);
            // 普通对象执行方法
            hero.adAttack();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取类的属性：
     * 1.使用传统方式
     * Hero hero = new Hero();
     * hero.name = "zhangsan";
     * 2.使用反射获取类的属性
     * 使用反射获取对象
     * Class<?> aClass = Class.forName(HERO_NAME);
     * Hero hero = (Hero)aClass.getConstructor().newInstance();
     * 通过反射获取对象的属性
     * Field filed = aClass.getField("name");  只能获取public属性，包括继承的属性
     * 或者 Field filed = aClass.getDeclaredField("pName")  可以获取所有的属性，但是不可以获取继承来的属性
     * <p>
     * <p>
     * 对字段设置值
     * field.set(hero,"李四光");
     * <p>
     * 注： 这里只能获取到private的字段，但并不能访问该private字段的值,除非加上 filed.setAccessible(true)
     */
    public void getObjectFiled() {
        try {
            Class<?> aClass = Class.forName(HERO_NAME);
            Hero hero = (Hero) aClass.getConstructor().newInstance();
            /**
             * 反射获取字段 有2种方式：
             *      1.getDeclaredField("age")： 可以获取本类中的所有属性，包括私有属性；不可以获取继承父类的属性
             *      2.getField("pName); 只能所有的public属性，包括父类的public 属性
             */
            //Field filed = aClass.getDeclaredField("pName");

            Field field = aClass.getField("name");
            field.setAccessible(true);
            field.set(hero, "李四光");
            // 注意： 通过反射获取类对象的属性，需要设置  setAccessible(true) 才可以访问
            System.out.println(field.get(hero));
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 读取配置文件，动态生成不同的对象
     */
    public void method03() {
        try {
            File file = new File(SRC);
            // 读取配置文件
            FileReader fileReader = new FileReader(file);
            char[] chars = new char[(int) file.length()];
            try {
                fileReader.read(chars);
                String className = new String(chars);
                Class<?> aClass = Class.forName(className);

                /*Constructor<?> constructor = aClass.getConstructor();
                Hero hero = (Hero)constructor.newInstance();
                hero.adAttack();*/

                Constructor<?>[] constructors = aClass.getConstructors();
                for (Constructor<?> constructor : constructors) {
                    Hero hero = (Hero) constructor.newInstance();
                    hero.adAttack();
                    System.out.println("");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 创建对象的方式：
     * 1。传统方式：  new Object();
     * 2。使用反射创建对象 :
     * 1）先通过反射获取类对象；Class.forName
     * 2）通过类对象获取构造器； Constructor constructor = Class.forName("").getConstructor();
     * 3) 通过构造器实例化一个对象 constructor.newInstance();
     */
    public void method02() {
        // 使用传统方式创建对象
        Hero hero1 = new Hero();
        hero1.name = "lisi";
        System.out.println(hero1);

        Hero hero = null;
        try {
            Class aClass = Class.forName(HERO_NAME);
            Constructor constructor = aClass.getConstructor();
            hero = (Hero) constructor.newInstance();
            hero.name = "zhangsan";
            System.out.println(hero);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("发生错误，错误信息为：" + e.getMessage());
        }


    }

    /**
     * 获取类对象有3种方式：
     * 1、Class.forName("包名.类名");  会初始化类属性；会执行静态代码块
     * 2、new 类名().getClass();  会初始化类属性；会执行静态代码块
     * 3、类名.class;  不会初始化类属性；不会执行静态代码块
     */
    public void getClassObject() {
        // 1.获取对象

        try {
            Class hero1 = Class.forName(HERO_NAME);

            Constructor constructor = hero1.getConstructor();
            Hero hero = (Hero) constructor.newInstance();

        } catch (Exception e) {
            e.printStackTrace();
        }
        // 2
        //Class<? extends Hero> aClass = new Hero().getClass();
        // 3
        //Class<Hero> heroClass = Hero.class;
    }
}
